/*
 * Copyright 2018 NingWei (ningww1@126.com)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * </p>
 */
/**
 * @author NingWei
 */
package com.kingdee.shr.ques.cloud.poi.excel;

import com.kingdee.shr.ques.cloud.enums.Code;
import com.kingdee.shr.ques.cloud.poi.common.Constant;
import com.kingdee.shr.ques.cloud.poi.common.StringUtil;
import com.kingdee.shr.ques.cloud.poi.entity.ExcelEntity;
import com.kingdee.shr.ques.cloud.poi.entity.ExcelPropertyEntity;
import com.kingdee.shr.ques.cloud.poi.function.ExportFunction;
import com.kingdee.shr.ques.cloud.utils.LoginInfoUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.*;

import static com.kingdee.shr.ques.cloud.poi.common.Constant.*;
import static com.kingdee.shr.ques.cloud.poi.common.DateFormatUtil.format;

/**
 * 导出具体实现类
 *
 * @author NingWei
 */
public class ExcelWriter {

    private JdbcTemplate jdbcTemplate; //数据库连接

    private Integer rowAccessWindowSize;
    private ExcelEntity excelEntity;
    private Integer pageSize;
    private Integer nullCellCount = 0;
    private Integer recordCountPerSheet;
    private XSSFCellStyle headCellStyle;
    private XSSFCellStyle requiredHeadCellStyle;
    private XSSFCellStyle descHeadCellStyle;
    private Map<Integer, Integer> columnWidthMap = new HashMap<Integer, Integer>();
    private Boolean openAutoColumWidth;
    private Integer headerIndex = 0; //表头开始行
    private List<String> descList = new ArrayList<>(); //填写备注信息

    private final static Logger log = LoggerFactory.getLogger(ExcelWriter.class);

    public ExcelWriter(ExcelEntity excelEntity, Integer pageSize, Integer rowAccessWindowSize, Integer recordCountPerSheet, Boolean openAutoColumWidth) {
        this.excelEntity = excelEntity;
        this.pageSize = pageSize;
        this.rowAccessWindowSize = rowAccessWindowSize;
        this.recordCountPerSheet = recordCountPerSheet;
        this.openAutoColumWidth = openAutoColumWidth;
    }

    public ExcelWriter(ExcelEntity excelEntity, Integer pageSize, Integer rowAccessWindowSize, Integer recordCountPerSheet, Boolean openAutoColumWidth, Integer headerIndex, List<String> descList) {
        this(excelEntity, pageSize, rowAccessWindowSize, recordCountPerSheet, openAutoColumWidth);
        //默认从第0行开始
        if (null != headerIndex) {
            this.headerIndex = headerIndex - 1;
        }
        if (null != descList) {
            this.descList = descList;
        }
    }

    /**
     * @param param
     * @param exportFunction
     * @param <P>
     * @param <T>
     * @return
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     * @throws ParseException
     * @throws IllegalAccessException
     */
    public <P, T> SXSSFWorkbook generateWorkbook(P param, ExportFunction<P, T> exportFunction) throws Exception {
        SXSSFWorkbook workbook = new SXSSFWorkbook(rowAccessWindowSize);
        int sheetNo = 1;
        int rowNum = 1;
        List<ExcelPropertyEntity> propertyList = excelEntity.getPropertyList();
        //初始化第一行
        SXSSFSheet sheet = generateHeader(workbook, propertyList, excelEntity.getFileName());
        //是否达到最大导出记录数
        boolean isReachMaxExportCount = false;
        //生成其他行
        int firstPageNo = 1;
        while (true) {
            // 处理总的导出记录数不能超过最大值
            if(Constant.EXPORT_MAX_COUNT <= firstPageNo * pageSize) {
                isReachMaxExportCount = true;
                //计算最后一次可导出的pagesize数据
                if(Constant.EXPORT_MAX_COUNT <= pageSize) {
                    pageSize = Constant.EXPORT_MAX_COUNT;
                }else {
                    if (Constant.EXPORT_MAX_COUNT < firstPageNo * pageSize) {
                        pageSize = Constant.EXPORT_MAX_COUNT - firstPageNo * pageSize;
                    }
                }

            }

            List<T> data = exportFunction.pageQuery(param, firstPageNo, pageSize);
            if (data == null || data.isEmpty()) {
                if (rowNum != 1) {
                    sizeColumWidth(sheet, propertyList.size());
                }
                log.warn("查询结果为空,结束查询!");
                break;
            }
            int dataSize = data.size();
            for (int i = 1; i <= dataSize; i++, rowNum++) {
                T queryResult = data.get(i - 1);
                Object convertResult = exportFunction.convert(queryResult);
                if (rowNum > MAX_RECORD_COUNT_PEER_SHEET) {
                    sizeColumWidth(sheet, propertyList.size());
                    sheet = generateHeader(workbook, propertyList, excelEntity.getFileName() + "_" + sheetNo);
                    sheetNo++;
                    rowNum = 1;
                    columnWidthMap.clear();
                }
                SXSSFRow row = sheet.createRow(rowNum);
                for (int j = 0; j < propertyList.size(); j++) {
                    SXSSFCell cell = row.createCell(j);
                    buildCellValue(cell, convertResult, propertyList.get(j));
                    calculateColumWidth(cell, j);
                }
                if (nullCellCount == propertyList.size()) {
                    log.warn("忽略一行空数据!");
                    sheet.removeRow(row);
                    rowNum--;
                }
                nullCellCount = 0;

            }
            //如果已经达到最大导出记录数，或已经导出所有数据，则退出
            if (isReachMaxExportCount || dataSize < pageSize) {
                sizeColumWidth(sheet, propertyList.size());
                log.warn("查询结果数量小于pageSize,结束查询!");
                break;
            }
            firstPageNo++;
        }
        return workbook;
    }


    /**
     * 构建模板Excel
     *
     * @return
     */
    public SXSSFWorkbook generateTemplateWorkbook() {
        SXSSFWorkbook workbook = new SXSSFWorkbook(rowAccessWindowSize);

        List<ExcelPropertyEntity> propertyList = excelEntity.getPropertyList();
        SXSSFSheet sheet = generateHeader(workbook, propertyList, excelEntity.getFileName());

        SXSSFRow row = sheet.createRow(1);
        for (int j = 0; j < propertyList.size(); j++) {
            SXSSFCell cell = row.createCell(j);
            cell.setCellValue(propertyList.get(j).getTemplateCellValue());
            calculateColumWidth(cell, j);
        }
        sizeColumWidth(sheet, propertyList.size());
        return workbook;
    }

    public SXSSFWorkbook generateTemplateWorkbook(List<Map<String, String>> output) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        SXSSFWorkbook workbook = new SXSSFWorkbook(rowAccessWindowSize);
        //判断是否有内容输出
        int sheets = 1;
        List<List<Map<String, String>>> subOutput = new ArrayList<>();
        if (!CollectionUtils.isEmpty(output)) {
            //分sheet导出
            final int seed = Constant.DEFAULT_RECORD_COUNT_PEER_SHEET;
            int index = 0;
            int dataSize = output.size();
            int time = dataSize / seed;

            while (index < time) {
                subOutput.add(output.subList(index * seed, (index + 1) * seed));
                index++;
            }
            if (index * seed < dataSize) {
                subOutput.add(output.subList(index * seed, dataSize));
            }
        }

        if (subOutput.size() == 0) {
            List<Map<String, String>> sub = new ArrayList<>();
            subOutput.add(sub);
        }

        List<ExcelPropertyEntity> propertyList = excelEntity.getPropertyList();
        sheets = subOutput.size();
        SXSSFSheet sheet  = null;

        //保存列表表头信息
        List<String> cellsName = new ArrayList<>();
        //设置Excel数据有效性校验信息（目前仅支持枚举和自定义SQL），目前只支持16个下拉值的设置
        String[] enumValidData = null; //获取枚举类型的下拉值
        int enumValidCellIndex = 0; //数据有效性列下标
        String[] sqlValidData = null; //获取之定义SQL的下拉值
        int sqlValidCellIndex = 0; //数据有效性列下标
        //TODO 判断有校验信息才进行处理，这个只需要进行一次即可
        for (int j = 0; j < propertyList.size(); j++) {
            cellsName.add(propertyList.get(j).getFieldEntity().getName());
            //设置下拉列表
            Class dataClazz = propertyList.get(j).getValidateData();
            String clazzName = propertyList.get(j).getValidateData().getName();
            if (!"java.lang.String".equalsIgnoreCase(clazzName)) {
                Object[] validDataContent = dataClazz.getEnumConstants();
                if (validDataContent.length > 0) {
                    int dataSize = validDataContent.length;
                    if(dataSize > Constant.VALID_SPINNER_COUNT) {
                        dataSize = Constant.VALID_SPINNER_COUNT;
                    }
                    enumValidData = new String[dataSize];
                    for (int i = 0; i < dataSize; i++) {
                        Code code = (Code) validDataContent[i];
                        enumValidData[i] = code.getDesc();
                    }
                    enumValidCellIndex = j;
                    continue;
                }
            }

            String validateSql = propertyList.get(j).getValidateSql();
            if (!StringUtils.isEmpty(validateSql)) {
                //判断validataSql是否包含eid参数
                if (validateSql.contains("#feid")) {
                    validateSql = validateSql.replaceAll("#feid", LoginInfoUtils.getCurrentEid());
                }
                List<String> queryData = jdbcTemplate.query(validateSql, new RowMapper() {
                    @Override
                    public Object mapRow(ResultSet resultSet, int i) throws SQLException {
                        return resultSet.getString(1);
                    }
                });

                if (queryData.size() > 0) {
                    int dataSize = queryData.size();
                    if(dataSize > Constant.VALID_SPINNER_COUNT) {
                        dataSize = Constant.VALID_SPINNER_COUNT;
                    }
                    sqlValidData = new String[dataSize];
                    for (int i = 0; i < dataSize; i++) {
                        sqlValidData[i] = queryData.get(i);
                    }
                    sqlValidCellIndex = j;
                    continue;
                }
            }
        }

        for (int k = 0; k < sheets; k++) {
            //生成表头信息
            sheet = generateHeader(workbook, propertyList, excelEntity.getFileName() + k);
            int rownum = this.headerIndex + 1;
            //设置数据有效性
            if(enumValidData != null) {
                addValidationData(sheet, rownum, Constant.VALID_SPINNER_MAX_COUNT, enumValidCellIndex, enumValidData);
            }
            if(sqlValidData != null) {
                addValidationData(sheet, rownum, Constant.VALID_SPINNER_MAX_COUNT, sqlValidCellIndex, sqlValidData);
            }

            //设置备注信息
            if (this.headerIndex > 0) {
                //存在备注信息，设置备注信息
                CellStyle descHeadCellStyle = getDescHeaderCellStyle(workbook, null);
                int lastDescIndex = this.headerIndex - 1;
                CellRangeAddress mergeCells = new CellRangeAddress(0, lastDescIndex, 0, cellsName.size() - 1);

                SXSSFRow content = sheet.createRow(0);
                //设置行高
                content.setHeight((short) 1800);
                SXSSFCell cell = content.createCell(0);
                StringBuffer sb = new StringBuffer("模板说明：\n");
                for (int i = 0; i < this.descList.size(); i++) {
                    sb.append((i + 1) + "、" + descList.get(i) + "；\n");
                }
                cell.setCellValue(sb.toString());
                cell.setCellStyle(descHeadCellStyle);
                sheet.addMergedRegion(mergeCells);
            }

            //填充其他内容
            if (!CollectionUtils.isEmpty(subOutput.get(k))) {
                for (Map map : subOutput.get(k)) {
                    SXSSFRow content = sheet.createRow(rownum++);
                    for (int i = 0; i < cellsName.size(); i++) {
                        // 如果是错误信息，采用红色字体显示
                        SXSSFCell cell = content.createCell(i);
                        cell.setCellValue((String) map.get(cellsName.get(i)));
                        if ("desc".equals(cellsName.get(i))) {
                            cell.setCellStyle(getDescHeaderCellStyle(workbook, null));
                        }
                    }
                }
            }

            sizeColumWidth(sheet, propertyList.size());
            columnWidthMap.clear();
        }

        return workbook;
    }

    /**
     * 构建多Sheet Excel
     *
     * @param param
     * @param exportFunction
     * @param <R>
     * @param <T>
     * @return
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     * @throws ParseException
     * @throws IllegalAccessException
     */
    public <R, T> SXSSFWorkbook generateMultiSheetWorkbook(R param, ExportFunction<R, T> exportFunction) throws Exception {
        int pageNo = 1;
        int sheetNo = 1;
        int rowNum = 1;
        SXSSFWorkbook workbook = new SXSSFWorkbook(rowAccessWindowSize);
        List<ExcelPropertyEntity> propertyList = excelEntity.getPropertyList();
        SXSSFSheet sheet = generateHeader(workbook, propertyList, excelEntity.getFileName());

        while (true) {
            List<T> data = exportFunction.pageQuery(param, pageNo, pageSize);
            if (data == null || data.isEmpty()) {
                if (rowNum != 1) {
                    sizeColumWidth(sheet, propertyList.size());
                }
                log.warn("查询结果为空,结束查询!");
                break;
            }
            for (int i = 1; i <= data.size(); i++, rowNum++) {
                T queryResult = data.get(i - 1);
                Object convertResult = exportFunction.convert(queryResult);
                if (rowNum > recordCountPerSheet) {
                    sizeColumWidth(sheet, propertyList.size());
                    sheet = generateHeader(workbook, propertyList, excelEntity.getFileName() + "_" + sheetNo);
                    sheetNo++;
                    rowNum = 1;
                    columnWidthMap.clear();
                }
                SXSSFRow bodyRow = sheet.createRow(rowNum);
                for (int j = 0; j < propertyList.size(); j++) {
                    SXSSFCell cell = bodyRow.createCell(j);
                    buildCellValue(cell, convertResult, propertyList.get(j));
                    calculateColumWidth(cell, j);
                }
                if (nullCellCount == propertyList.size()) {
                    log.warn("忽略一行空数据!");
                    sheet.removeRow(bodyRow);
                    rowNum--;
                }
                nullCellCount = 0;
            }
            if (data.size() < pageSize) {
                sizeColumWidth(sheet, propertyList.size());
                log.warn("查询结果数量小于pageSize,结束查询!");
                break;
            }
            pageNo++;
        }
        return workbook;
    }

    /**
     * 自动适配中文单元格
     *
     * @param sheet
     */
    private void sizeColumWidth(SXSSFSheet sheet, Integer columnSize) {
        if (openAutoColumWidth) {
            for (int j = 0; j < columnSize; j++) {
                if (columnWidthMap.get(j) != null) {
                    sheet.setColumnWidth(j, columnWidthMap.get(j) * 256);
                }
            }
        }
    }

    /**
     * 自动适配中文单元格
     *
     * @param cell
     * @param columnIndex
     */
    private void calculateColumWidth(SXSSFCell cell, Integer columnIndex) {
        if (openAutoColumWidth) {
            String cellValue = cell.getStringCellValue();
            int length = cellValue.getBytes().length;
            length += (int) Math.ceil((double) ((cellValue.length() * 3 - length) / 2) * 0.1D);
            length = Math.max(length, CHINESES_ATUO_SIZE_COLUMN_WIDTH_MIN);
            length = Math.min(length, CHINESES_ATUO_SIZE_COLUMN_WIDTH_MAX);
            if (columnWidthMap.get(columnIndex) == null || columnWidthMap.get(columnIndex) < length) {
                columnWidthMap.put(columnIndex, length);
            }
        }
    }

    /**
     * 初始化第一行的属性
     *
     * @param workbook
     * @param propertyList
     * @param sheetName
     * @return
     */
    private SXSSFSheet generateHeader(SXSSFWorkbook workbook, List<ExcelPropertyEntity> propertyList, String sheetName) {
        SXSSFSheet sheet = workbook.createSheet(sheetName);
        SXSSFRow headerRow = sheet.createRow(this.headerIndex);
        headerRow.setHeight((short) 600);
        CellStyle headCellStyle = getHeaderCellStyle(workbook);
        CellStyle requiredHeadCellStyle = getReqiredHeaderCellStyle(workbook, null);
        for (int i = 0; i < propertyList.size(); i++) {
            SXSSFCell cell = headerRow.createCell(i);
            if (null != propertyList.get(i).getRequired() && propertyList.get(i).getRequired()) {
                //必填项
                cell.setCellStyle(requiredHeadCellStyle);
            } else {
                cell.setCellStyle(headCellStyle);
            }
            cell.setCellValue(propertyList.get(i).getColumnName());
            calculateColumWidth(cell, i);
        }
        return sheet;
    }

    /**
     * 构造 除第一行以外的其他行的列值
     *
     * @param cell
     * @param entity
     * @param property
     */
    private void buildCellValue(SXSSFCell cell, Object entity, ExcelPropertyEntity property) throws Exception {
        Field field = property.getFieldEntity();
        Object cellValue = field.get(entity);
        if (StringUtil.isBlank(cellValue) || "0".equals(cellValue.toString()) || "0.0".equals(cellValue.toString()) || "0.00".equals(cellValue.toString())) {
            nullCellCount++;
        }
        if (cellValue == null) {
            cell.setCellValue("");
        } else if (cellValue instanceof BigDecimal) {
            if (-1 == property.getScale()) {
                cell.setCellValue(cellValue.toString());
            } else {
                cell.setCellValue((((BigDecimal) cellValue).setScale(property.getScale(), property.getRoundingMode())).toString());
            }
        } else if (cellValue instanceof Date) {
            cell.setCellValue(format(property.getDateFormat(), (Date) cellValue));
        } else {
            cell.setCellValue(cellValue.toString());
        }
    }


    public CellStyle getHeaderCellStyle(SXSSFWorkbook workbook) {
        if (headCellStyle == null) {
            headCellStyle = workbook.getXSSFWorkbook().createCellStyle();
            headCellStyle.setBorderTop(BorderStyle.NONE);
            headCellStyle.setBorderRight(BorderStyle.NONE);
            headCellStyle.setBorderBottom(BorderStyle.NONE);
            headCellStyle.setBorderLeft(BorderStyle.NONE);
            headCellStyle.setAlignment(HorizontalAlignment.CENTER);
            headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            XSSFColor color = new XSSFColor(new java.awt.Color(217, 217, 217));
            headCellStyle.setFillForegroundColor(color);
            headCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            Font font = workbook.createFont();
            font.setFontName("微软雅黑");
            //默认为黑色字体
            font.setColor(IndexedColors.BLACK.index);
            font.setBold(true);
            headCellStyle.setFont(font);
            headCellStyle.setDataFormat(workbook.createDataFormat().getFormat("@"));
        }
        return headCellStyle;
    }

    /**
     * @return
     * @author Miaoxiong Fan
     * @description 获取表头必填信息单元格格式
     * @date 2019/2/1
     * @Param
     */
    public CellStyle getReqiredHeaderCellStyle(SXSSFWorkbook workbook, IndexedColors input) {
        if (requiredHeadCellStyle == null) {
            requiredHeadCellStyle = workbook.getXSSFWorkbook().createCellStyle();
            requiredHeadCellStyle.setBorderTop(BorderStyle.NONE);
            requiredHeadCellStyle.setBorderRight(BorderStyle.NONE);
            requiredHeadCellStyle.setBorderBottom(BorderStyle.NONE);
            requiredHeadCellStyle.setBorderLeft(BorderStyle.NONE);
            requiredHeadCellStyle.setAlignment(HorizontalAlignment.CENTER);
            requiredHeadCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            XSSFColor color = new XSSFColor(new java.awt.Color(217, 217, 217));
            requiredHeadCellStyle.setFillForegroundColor(color);
            requiredHeadCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            Font font = workbook.createFont();
            font.setFontName("微软雅黑");
            //默认为黑色字体
            if (null == input) {
                font.setColor(IndexedColors.RED.index);
            } else {
                font.setColor(input.index);
            }
            font.setBold(true);
            requiredHeadCellStyle.setFont(font);
            requiredHeadCellStyle.setDataFormat(workbook.createDataFormat().getFormat("@"));
        }
        return requiredHeadCellStyle;
    }

    /**
     * @return
     * @author Miaoxiong Fan
     * @description 获取备注信息单元格格式
     * @date 2019/2/1
     * @Param
     */
    public CellStyle getDescHeaderCellStyle(SXSSFWorkbook workbook, IndexedColors input) {
        if (descHeadCellStyle == null) {
            descHeadCellStyle = workbook.getXSSFWorkbook().createCellStyle();
            descHeadCellStyle.setAlignment(HorizontalAlignment.LEFT);
            descHeadCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            Font font = workbook.createFont();
            font.setFontName("微软雅黑");
            //默认为红色字体
            if (null == input) {
                font.setColor(IndexedColors.RED.index);
            } else {
                font.setColor(input.index);
            }
            font.setBold(false);
            descHeadCellStyle.setFont(font);
            descHeadCellStyle.setWrapText(true);
            descHeadCellStyle.setDataFormat(workbook.createDataFormat().getFormat("@"));
        }
        return descHeadCellStyle;
    }

    /**
     * @return
     * @author Miaoxiong Fan
     * @description 获取默认的备注信息
     * @date 2019/2/1
     * @Param
     */
    public static List<String> getCommonDescList() {
        List<String> commonDescList = new ArrayList<>();
        commonDescList.add("红色字体为必填项");
        commonDescList.add("当导入方式为覆盖导入时，若编码在系统中不存在，则新增，存在则覆盖");
        return commonDescList;
    }

    /**
     * @return
     * @author Miaoxiong Fan
     * @description 设置单元格下拉列表
     * @date 2019/2/1
     * @Param
     */
    private void addValidationData(Sheet sheet, int firstRow, int lastRow, int cellIndex, String[] list) {
        if (null == list) {
            return;
        }

        if (firstRow < 0 || lastRow < 0 || cellIndex < 0 || lastRow < firstRow) {
            throw new IllegalArgumentException("Wrong Row or Column index : " + firstRow + ":" + lastRow + ":" + cellIndex + ":" + cellIndex);
        }

        //限制list个数不能超过16个
        String[] dataList = null;
        if (list.length > 16) {
            dataList = new String[16];
            for (int i = 0; i < 16; i++) {
                dataList[i] = dataList[i];
            }
        } else {
            dataList = list;
        }

        //加载下拉列表内容
        DataValidationHelper helper = sheet.getDataValidationHelper();
        XSSFDataValidationConstraint constraint = (XSSFDataValidationConstraint) helper.createExplicitListConstraint(dataList);
        //设置下拉框位置
        CellRangeAddressList addressList = new CellRangeAddressList(firstRow, lastRow, cellIndex, cellIndex);
        DataValidation dataValidation = helper.createValidation(constraint, addressList);
        //处理Excel兼容性问题
        dataValidation.setSuppressDropDownArrow(true);
        sheet.addValidationData(dataValidation);
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}
